import socket
import time
import xmlrpc.client as xc
from datetime import datetime as dt
from dataflow.conf import notify_emails
from bigdata_imei.common.exchange_mail_util import ExchangeUtil


def get_host_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()

    return ip

rpc_url = 'http://127.0.0.1:9001'

class Monitor(object):
    def __init__(self, interval=300):
        self.interval = interval
        self.fatal_dict = {}
        self.sms_groups = {}
        self.fatals = 0
        self.runnings = 0
        self.host = get_host_ip()

    def connect_supervisor(self, rpc_url):
        try:
            client = xc.Server('%s/RPC2' % rpc_url)
            server_state = client.supervisor.getState()['statecode']
        except Exception as e:
            # can not connect to supervisor
            return None
        # FATAL : 2
        if server_state == 2:
            return None
        return client


    def send_sms(self, process_name, fatal=True):
        if fatal:
            msg = "处于FATAL或EXITED状态, 请尽快查看!"
        else:
            msg = "成功恢复!"
        content = "%s的进程%s%s" % (self.host, process_name, msg)
        print("[%s] host %s's process %s %s " % (dt.today(), self.host, process_name, "fatal" if fatal else "recovered"))
        mail = ExchangeUtil('Supervisor异常', notify_emails)
        mail.set_content(content)
        mail.send()


    def handle_stats(self, process_name, process_status):
        now = time.time()
        # FATAL: 200, EXITED: 100

        print(process_name, process_status)
        if process_status in (0, 100, 200):
            self.fatals += 1
            if process_name in self.fatal_dict:
                last_warn_time = self.fatal_dict[process_name]
                if now - last_warn_time < 60 * 30:
                    return
            self.fatal_dict[process_name] = now
            self.send_sms(process_name)
        # RUNNING: 20
        elif process_status == 20:
            self.runnings += 1
            # If process turn from FATAL to RUNNING, then send success sms
            if process_name in self.fatal_dict:
                self.fatal_dict.pop(process_name)
                self.send_sms(process_name, False)


    def monitor_stats(self, rpc_url):
        client = self.connect_supervisor(rpc_url)
        process = 'SUPERVISOR'
        if client is None:
            now = time.time()
            if process in self.fatal_dict:
                last_warn_time = self.fatal_dict[process]
                if now - last_warn_time < 60 * 20:
                    return 'FATAL'
            self.fatal_dict[process] = now
            self.send_sms(process)
            return 'FATAL'

        #恢复后去除
        if process in self.fatal_dict:
            self.fatal_dict.pop(process)

        for process_stats in client.supervisor.getAllProcessInfo():
            self.handle_stats(process_stats['name'], process_stats['state'])
        return 'RUNNING'


    def clear_history(self):
        now = time.time()
        self.fatals = 0
        self.runnings = 0
        for process in self.fatal_dict.keys():
            print(process, self.fatal_dict[process])
            if now - self.fatal_dict[process] > 60 * 60 * 12:
                self.fatal_dict.pop(process)


    def run(self):
        while True:
            state = self.monitor_stats(rpc_url)
            print("[%s] Host %s's supervisor is %s, has %d fatals, %d runnings" % (dt.today(), self.host, state,
                                                                                   self.fatals, self.runnings))
            self.clear_history()
            time.sleep(self.interval)

if __name__ == '__main__':
    Monitor().run()
